package broadcast

type Domain struct {
	join chan chan interface{}
	leave chan chan interface{}
	msg chan interface{}
	members map[chan interface{}] chan interface{}
}

type member struct {
	notify chan interface{}
	leave chan chan interface{}
}

func (d *Domain) Join () *member {

	m := &member{make(chan interface{}), d.leave}
	d.join <- m.notify

	return m
}

func (d *Domain) Send (msg interface{}) {

	d.msg <- msg
}

func (m *member) Leave () {

	m.leave <- m.notify
	m.leave = nil
	m.notify = nil
}

func (m *member) Recv () interface{} {

	return <-m.notify
}

func New() *Domain {

	d := &Domain{
		make(chan chan interface{}), 
		make(chan chan interface{}), 
		make(chan interface{}), 
		make(map[chan interface{}]chan interface{})}

	go func () {

		for {
			select {
			case notify := <-d.join:
				d.members[notify] = notify
			case notify := <-d.leave:
				d.members[notify] = nil, false
			case msg := <-d.msg:
				for notify, _ := range (d.members) {
					go func (notify chan interface{}, msg interface{}) {
						notify <- msg
					}	(notify, msg)
				}
			}
		}
	} ()

	return d
}
